package warthog.scangen;

import java.io.IOException;
import java.util.*;


final public class Color {
	static final ArrayList<Color> rainbow = new ArrayList<Color>();
	List<DNode> members;
	final int index;
	final DNode rep;
	private Color(DNode rep, List<DNode> members) {
		this.rep = rep;
		this.members = members;
		for (DNode n:this.members) n.color = this;
		index = rainbow.size();
		rainbow.add(this);
	}
	private boolean trySplit() {
		ArrayList<DNode> same = new ArrayList<DNode>();
		ArrayList<DNode> different = new ArrayList<DNode>();
		for (DNode candidate:members) {
			if (rep.isDistinct(candidate)) different.add(candidate);
			else same.add(candidate);
		}
		if (different.size()>0) {
			members = same;
			new Color(different.get(0), different);
			return true;
		} else return false;
	}
	public static void minimize() {
		// We'd like to guarantee that the dead state gets color zero.
		// That way, it's easy later to test for a dead state machine.
		// To make that happen, we need to decide which DNode represents the color.
		DNode dead = DNode.fetch(new HashSet<Node>());
		new Color(dead, new ArrayList<DNode>(DNode.all()));
		boolean more;
		do {
			more = false;
			for (int i=0; i<rainbow.size(); i++) if (rainbow.get(i).trySplit()) more = true;
		} while (more);
	}
	public static void writeData(StringBuilder w) throws IOException {
		//w.write("// Color.writeData(...)\n");
		// Write acceptance array
		w.append("  private int[] accept = {");
		for(Color c:rainbow)  c.rep.codeAccept(w);
		w.append("};\n");
		// Write bounds array
		w.append("  private int[][] bounds = {\n");
		for(Color c:rainbow)  c.rep.codeBounds(w);
		w.append("  };\n");
		// Write edges array
		w.append("  private int[][] edges = {\n");
		for(Color c:rainbow)  c.rep.codeEdges(w);
		w.append("  };\n");
	}
}
